/*
   Copyright (C) 2004/2006/2007 Kai Sterker <kaisterker@linuxgames.com>
   Adapted as C library 2009 Klaus Blindert <klaus.blindert@web.de>

   Originally part of the Adonthell Project http://adonthell.linuxgames.com.
   Part of the libABF project.

   libABF is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef ABF_FLAT_H
#define ABF_FLAT_H

#include "abf_types.h"

typedef enum
{
    ABF_T_UNKNOWN = -1,
    ABF_T_BOOL = 0,
    ABF_T_CHAR = 1,
    ABF_T_UINT8 = 2,
    ABF_T_SINT8 = 3,
    ABF_T_UINT16 = 4,
    ABF_T_SINT16 = 5,
    ABF_T_UINT32 = 6,
    ABF_T_SINT32 = 7,
    ABF_T_STRING = 8,
    ABF_T_FLOAT = 9,
    ABF_T_DOUBLE = 10,
    ABF_T_BLOB = 11,
    ABF_T_FLAT = 12,
    NBR_TYPES = 13
} abf_data_type;

#define ABF_NOLIMIT (-1)

typedef struct abf_flat_data abf_flat_data_t;
typedef struct abf_flat abf_flat_t;

/**
  * @name Methods to manage flattened data
  */
/**@{*/
/**
 * Allocate and initialise a new flat.
 */
abf_flat_t* abf_create();

/**
 * Destroy a flat created by abf_flat_create.
 */
void abf_destroy(abf_flat_t* flat);

/**
 * Copy a flat into another (already created) flat.
 */
void abf_copy(abf_flat_t* dst, abf_flat_t* src);

/**
  * Dump the contents of the flat to @b stdout.
  */
void abf_dump(abf_flat_t* flat, int recurse);
/**@}*/

/**
  * @name Methods to flatten data
  */
/**@{*/
/**
 * Store a boolean value.
 * @param name id used to retrieve the value later on.
 * @param b value to store.
 */
void abf_put_bool (abf_flat_t* flat, const char* name, int b);

/**
  * Store 8 bit unsigned integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_uint8 (abf_flat_t* flat, const char* name, u_int8 i);

/**
  * Store 8 bit signed integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_sint8 (abf_flat_t* flat, const char* name, s_int8 i);

/**
  * Store 16 bit unsigned integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_uint16 (abf_flat_t* flat, const char* name, u_int16 i);

/**
  * Store 16 bit signed integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_sint16 (abf_flat_t* flat, const char* name, s_int16 i);

/**
  * Store 32 bit unsigned integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_uint32 (abf_flat_t* flat, const char* name, u_int32 i);

/**
  * Store 32 bit signed integer value.
  * @param name id used to retrieve the value later on.
  * @param i value to store.
  */
void abf_put_sint32 (abf_flat_t* flat, const char* name, s_int32 i);

/**
  * Store character string.
  * @param name id used to retrieve the value later on.
  * @param s string to store.
  */
void abf_put_string (abf_flat_t* flat, const char* name, const char* s);

/**
  * Store floating point value.
  * @param name id used to retrieve the value later on.
  * @param f value to store.
  */
void abf_put_float (abf_flat_t* flat, const char* name, float f);

/**
  * Store double value.
  * @param name id used to retrieve the value later on.
  * @param d value to store.
  */
void abf_put_double (abf_flat_t* flat, const char* name, double d);

/**
  * Store binary data of arbitrary length.
  * @param name id used to retrieve the value later on.
  * @param b binary data to store.
  * @param size length of data stored.
  */
void abf_put_block (abf_flat_t* flat, const char* name, void *b, u_int32 size);

/**
  * Store another flat. Used to create nested structures for easier
  * and safer value retrieval.
  * @param name id used to retrieve the value later on.
  * @param out flat to store.
  */
void abf_put_flat (abf_flat_t* flat, const char* name, abf_flat_t* sub);
/**@}*/

/**
  * @name Methods to retrieve flattened data
  */
/**@{*/
/**
  * Retrieve a boolean value previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @param optional whether to gracefully ignore missing data.
  * @return value stored or \b false on error.
  */
int abf_get_bool (abf_flat_t* flat, const char* name);

/**
  * Retrieve a boolean value previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @param optional default value.
  * @return value stored or \b default on error.
  */
int abf_getopt_bool (abf_flat_t* flat, const char* name, int optional);

/**
  * Retrieve 8 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0 on error.
  */
u_int8 abf_get_uint8 (abf_flat_t* flat, const char* name);

/**
  * Retrieve 8 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @param optional default value.
  * @return value stored or \b 0 on error.
  */
u_int8 abf_getopt_uint8 (abf_flat_t* flat, const char* name, u_int8 optional);

/**
  * Retrieve 8 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b -1 on error.
  */
s_int8 abf_get_sint8 (abf_flat_t* flat, const char* name);


/**
  * Retrieve 8 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @param optional default value.
  * @return value stored or \b optional on error.
  */
s_int8 abf_getopt_sint8 (abf_flat_t* flat, const char* name, s_int8 optional);

/**
  * Retrieve 16 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0 on error.
  */
u_int16 abf_get_uint16 (abf_flat_t* flat, const char* name);

/**
  * Retrieve 16 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b optional on error.
  */
u_int16 abf_getopt_uint16 (abf_flat_t* flat, const char* name, u_int16 optional);

/**
  * Retrieve 16 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b -1 on error.
  */
s_int16 abf_get_sint16 (abf_flat_t* flat, const char* name);

/**
  * Retrieve 16 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b -1 on error.
  */
s_int16 abf_getopt_sint16 (abf_flat_t* flat, const char* name, s_int16 optional);

/**
  * Retrieve 32 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0 on error.
  */
u_int32 abf_get_uint32 (abf_flat_t* flat, const char* name);

/**
  * Retrieve 32 bit unsigned integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b optional on error.
  */
u_int32 abf_getopt_uint32 (abf_flat_t* flat, const char* name, u_int32 optional);

/**
  * Retrieve 32 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b -1 on error.
  */
s_int32 abf_get_sint32 (abf_flat_t* flat, const char* name);

/**
  * Retrieve 32 bit signed integer previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b -1 on error.
  */
s_int32 abf_getopt_sint32 (abf_flat_t* flat, const char* name, s_int32 optional);

/**
  * Retrieve string previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b "" (empty string) on error.
  */
char* abf_get_string (abf_flat_t* flat, const char* name);

/**
  * Retrieve string previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b "" (empty string) on error.
  */
char* abf_getopt_string (abf_flat_t* flat, const char* name, const char* optional);

/**
  * Retrieve floating point number previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0.0 on error.
  */
float abf_get_float (abf_flat_t* flat, const char* name);

/**
  * Retrieve floating point number previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0.0 on error.
  */
float abf_getopt_float (abf_flat_t* flat, const char* name, float optional);

/**
  * Retrieve double value previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0.0 on error.
  */
double abf_get_double (abf_flat_t* flat, const char* name);

/**
  * Retrieve double value previously stored with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b 0.0 on error.
  */
double abf_getopt_double (abf_flat_t* flat, const char* name, double optional);

/**
  * Retrieve a nested flat with given id. Call
  * success() to check whether value retrieval was successful.
  * @param name id used to retrieve the value later on.
  * @return value stored or \b empty flat on error.
  */
abf_flat_t* abf_get_flat (abf_flat_t* flat, const char* name);
/**@}*/

/**
  * @name Methods to traverse flattened data
  *
  * These methods are for @b advanced usage.
  */
/**@{*/
/**
  * Find named data entry, parse if necessary, wrap if necessary, untyped.
  */
abf_flat_data_t* abf_flat_find(abf_flat_t* flat, const char* name);

/**
  * Seek to a data entry.
  */
abf_flat_data_t* abf_flat_seek(abf_flat_t* flat, u_int32 i);

/**
  * Get current data entry. Returns @b NULL if the end of the flat is reached.
  */
abf_flat_data_t* abf_flat_current(abf_flat_t* flat);

/**
  * Advance one data entry.
  */
void abf_flat_advance(abf_flat_t* flat);
/**@}*/

/**
  * @name Methods to introspect data entries.
  *
  * These methods are for @b advanced usage.
  */
/**@{*/
const char* abf_flat_gettypename(abf_data_type data);
abf_data_type abf_flat_gettype(abf_flat_data_t* data);
abf_data_type abf_flat_gettypeforname(const char* name);
void abf_flat_getcontent(abf_flat_data_t* data, char**content, u_int32* size);
char* abf_flat_getname(abf_flat_data_t* data);
const char* abf_flat_tostring(abf_flat_data_t* data);
abf_flat_t* abf_flat_toflat(abf_flat_data_t* data);
/**@}*/


/**
  * @name Miscallenous methods.
  *
  * These methods are for @b advanced usage.
  */
/**@{*/
/**
  * Set the buffer of the flat, the contents are NOT copied.
  * The flat takes ownership.
  */
void abf_flat_setbuffer(abf_flat_t* flat, char *buffer, u_int32 size);

/**
  * Get the buffer of the flat, the contents are NOT copied.
  * The flat keeps ownership.
  */
void abf_flat_getbuffer(abf_flat_t* flat, char **buffer, u_int32 *size);

/**
  * Calculate the adler32 checksum.
  */
u_int32 abf_flat_checksum(abf_flat_t* flat);
/**@}*/

#endif // ABF_FLAT_H
